#include <defs.h>
#include <messages.h>
#include <bwio.h>
#include <user.h>
#include <string.h>

int Create( int priority, void (*func) (), char *name ) {
  asm volatile ("swi %0" : : "i" (SYSCALL_CREATE));
    
  // NOTE: this is essentially a hack to avoid a compiler warning.
  int ret;
  asm volatile ("mov %0, r0" : "=ir" (ret));
  return ret;
}

int MyTid() {
  asm volatile ("swi %0" : : "i" (SYSCALL_MY_TID));
  int ret;
  asm volatile ("mov %0, r0" : "=ir" (ret));
  return ret;
}

int MyParentTid() {
  asm volatile ("swi %0" : : "i" (SYSCALL_MY_PARENT_TID));
  int ret;
  asm volatile ("mov %0, r0" : "=ir" (ret));
  return ret;
}

void Pass() {
  asm volatile ("swi %0" : : "i" (SYSCALL_PASS));
}

void Exit() {
  asm volatile ("swi %0" : : "i" (SYSCALL_EXIT));
}

void FingerOfDeath() {
  asm volatile ("swi %0" : : "i" (SYSCALL_FINGER_OF_DEATH));
}

int Send( int tid, char *msg, int msglen, char *reply, int replylen ) {
  asm volatile ("swi %0" : : "i" (SYSCALL_SEND));
  int ret;
  asm volatile ("mov %0, r0" : "=ir" (ret));
  return ret;
}

int Receive( int *tid, char *msg, int len ) {
  asm volatile ("swi %0" : : "i" (SYSCALL_RECEIVE));
  int ret;
  asm volatile ("mov %0, r0" : "=ir" (ret));
  return ret;
}

int Reply( int tid, char *reply, int len ) {
  asm volatile ("swi %0" : : "i" (SYSCALL_REPLY));
  int ret;
  asm volatile ("mov %0, r0" : "=ir" (ret));
  return ret;
}

int RegisterAs(char *name) {
  name_req request;
  request.type = REGISTER_AS_REQUEST;
  StringCopy(request.name, name);
  int reply;
  
	Send(1, (char*)( &request ), sizeof(name_req),
      (char*)( &reply ), sizeof(int));
	if (reply == ERROR_TABLE_FULL)
    Panic("RegisterAs", "NameServer table full; could not register");
  return reply;
}

int WhoIs(char *name) {
  name_req request;
  request.type = WHO_IS_REQUEST;
  StringCopy(request.name, name);
  int reply;
  
	Send(1, (char*)( &request ), sizeof(name_req),
      (char*)( &reply ), sizeof(int));
  if (reply == ERROR_TASK_NOT_FOUND)
    Panic("WhoIs", name);
	return reply;
}

int Delay(int ticks) {
  int clockserver_tid = WhoIs("clock-server");
  clock_req msg;
  msg.type = DELAY_REQUEST;
  msg.ticks = ticks;
  Send(clockserver_tid, (char*)( &msg ), sizeof(clock_req), NULL, 0);
  return SUCCESS;
}

int Time() {
  int clockserver_tid = WhoIs("clock-server");
  clock_req msg;
  msg.type = TIME_REQUEST;
  int time;
  Send(clockserver_tid, (char*)( &msg ), sizeof(clock_req),
      (char*)( &time ), sizeof(int));
  return time;
}

int DelayUntil(int ticks) {
  int clockserver_tid = WhoIs("clock-server");
  clock_req msg;
  msg.type = DELAY_UNTIL_REQUEST;
  msg.ticks = ticks;
  Send(clockserver_tid, (char*)( &msg ), sizeof(clock_req), NULL, 0);
  return SUCCESS;
}

int AwaitEvent( int eventid, char *event, int eventlen ) {
  asm volatile ("swi %0" : : "i" (SYSCALL_AWAIT_EVENT));
  int ret;
  asm volatile ("mov %0, r0" : "=ir" (ret));
  return ret;
}

int Putc( int channel, char c) {
  int serialserver_tid;
  char msg = c;
  switch (channel) {
    case COM1:
      serialserver_tid = WhoIs("train-tx-server");
      Send( serialserver_tid, &msg, 1, NULL, 0 );
      break;
    case COM2:
      serialserver_tid = WhoIs("terminal-tx-server");
      Send( serialserver_tid, &msg, 1, NULL, 0 );
      break;
    default:
      Panic("Putc", "invalid channel");
      break;
  }
  return SUCCESS;
}

int PutStr(char *msg, int n) {
  int serialserver_tid = WhoIs("terminal-tx-server");   
  Send( serialserver_tid, msg, n, NULL, 0 );
  return SUCCESS;
}

int Getc( int channel ) {
  int serialserver_tid;
  rx_reply reply;
  
  switch (channel) {
    case COM1:
      serialserver_tid = WhoIs("train-rx-server");
      break;
    case COM2:
      serialserver_tid = WhoIs("terminal-rx-server");
      break;
    default:
      bwprintf(COM2, "---CHANNEL: %d\r\n", channel);
      Panic("Getc", "Invalid channel parameter.");
  }
  Send( serialserver_tid, NULL, 0, (char*)&reply, sizeof(rx_reply) );
  // TODO: error checking
  return reply.ch;
}

void Panic(char *fun_name, char *msg) {
  asm volatile ("swi %0" : : "i" (SYSCALL_PANIC));
}

int ParamTest(int a, int b, int c, int d, int e) {
  asm volatile ("swi %0" : : "i" (SYSCALL_PARAMTEST));
  int ret;
  asm volatile ("mov %0, r0" : "=ir" (ret));
  return ret;
}
